package cn.yangliu.webflux;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

import lombok.SneakyThrows;

/**
 * @author 杨柳
 * @date 2019-05-18
 */
public class EntityScanner {

    @SneakyThrows
    public static void main(String[] args) {
        test("cn.yangliu.webflux.entity");
    }


    @SneakyThrows
    public static void test(String packageName) {
        assert Objects.nonNull(packageName) : "包名为空";

        String path = packageName.replace(".", File.separator);

        Enumeration<URL> resources = Thread.currentThread().getContextClassLoader().getResources(
                path);

        while (resources.hasMoreElements()) {

            URL url = resources.nextElement();

            String filePath = URLDecoder.decode(url.getFile(), "UTF-8");


            File file = new File(filePath);

            loop(file, path);
        }


    }

    /**
     * 递归遍历子包中的class
     * @param file
     * @param path
     */
    @SneakyThrows
    public static void loop(File file, String path) {

        if (!file.isFile()) {

            File[] files = file.listFiles();
            if (Objects.isNull(files)) {
                return;
            }
            for (File f : files) {
                loop(f, path);
            }
            return;
        }

        //磁盘中的绝对路径
        String absolutePath = file.getAbsolutePath();
        String prefix = absolutePath.substring(0, absolutePath.indexOf(path));
        String temp = absolutePath.replace(prefix, "");
        String className = temp.replace(File.separator, ".").substring(0, temp.lastIndexOf("."));

        //加载类 获得class对象
        Class<?> clazz = MyClassLoader.INSTANCE.loadClass(file, className);

        //初始化对象,调用set get方法
        initObj(clazz);

    }

    @SneakyThrows
    public static void initObj(Class<?> clazz) {
        Object o = clazz.newInstance();

        //用set是为了去重
        Set<Field> fieldList = new HashSet<>();

        Class<?> loopClass = clazz;
        //获取所有的属性,包括父类的
        while (!loopClass.equals(Object.class)) {
            Field[] fields = loopClass.getDeclaredFields();
            fieldList.addAll(Arrays.asList(fields));

            loopClass = loopClass.getSuperclass();
        }

        for (Field field : fieldList) {
            //排除代理属性和静态属性
            if (field.isSynthetic() || Modifier.isStatic(field.getModifiers())) {
                continue;
            }

            String fieldName = field.getName();

            String prefix = fieldName.substring(0, 1);
            String sufix = fieldName.substring(1);
            String temp = prefix.toUpperCase();

            String getter = "get" + temp + sufix;
            String setter = "set" + temp + sufix;

            Class<?> fieldType = field.getType();
            //执行get set 方法
            invokeSetter(setter, fieldType, clazz, o);
            invokeGetter(getter, clazz, o);
        }

    }


    @SneakyThrows
    public static void invokeSetter(String methodName, Class<?> fiedType, Class<?> classType, Object obj) {
        Method setter = null;

        Class<?> loopClass = classType;
        // 从当前类和父类中寻找set 方法
        while (!loopClass.equals(Object.class)) {
            try {
                setter = loopClass.getDeclaredMethod(methodName, fiedType);
                if (Objects.nonNull(setter)) {
                    break;
                }
            } catch (Exception e) {
                System.out.println(loopClass + "没找到方法" + e.getMessage());
                loopClass = loopClass.getSuperclass();
            }
        }

        if (Objects.nonNull(setter)) {

            setter.invoke(obj, (Object) null);

        }
    }

    @SneakyThrows
    public static void invokeGetter(String methodName, Class<?> classType, Object obj) {
        Method getter = null;

        Class<?> loopClass = classType;
        // 从当前类和父类中寻找get 方法
        while (!loopClass.equals(Object.class)) {
            try {
                getter = loopClass.getDeclaredMethod(methodName);
                if (Objects.nonNull(getter)) {
                    break;
                }
            } catch (Exception e) {
                System.out.println(loopClass + "没找到方法" + e.getMessage());
                loopClass = loopClass.getSuperclass();
            }
        }

        if (Objects.nonNull(getter)) {
            getter.invoke(obj);
        }
    }

    //自定义类加载器
    static class MyClassLoader extends ClassLoader {

        public final static MyClassLoader INSTANCE = new MyClassLoader();

        @SneakyThrows
        public Class<?> loadClass(File file, String className) {
            InputStream is = new FileInputStream(file);
            int available = is.available();
            byte[] bytes = new byte[available];
            is.read(bytes);
            is.close();
            return defineClass(className, bytes, 0, available);
        }

    }

}
